home *** CD-ROM | disk | FTP | other *** search
- /******************************************************************************
- * Bzr_Sym.c - Bezier symbolic computation. *
- *******************************************************************************
- * Written by Gershon Elber, Sep. 92. *
- ******************************************************************************/
-
- #include "cagd_loc.h"
-
- /******************************************************************************
- * Given two bezier curves - multiply them coordinatewise. *
- * The two curves are promoted to same point type before the multiplication *
- * can take place. *
- * Return a bezier curve representing their product. *
- ******************************************************************************/
- CagdCrvStruct *BzrCrvMult(CagdCrvStruct *Crv1, CagdCrvStruct *Crv2)
- {
- CagdBType IsNotRational;
- int i, j, k, MaxCoord, Order,
- Order1 = Crv1 -> Order,
- Order2 = Crv2 -> Order,
- Degree1 = Order1 - 1,
- Degree2 = Order2 - 1;
- CagdCrvStruct *ProdCrv;
- CagdRType **Points, **Points1, **Points2;
-
- if (!CAGD_IS_BEZIER_CRV(Crv1) || !CAGD_IS_BEZIER_CRV(Crv2))
- FATAL_ERROR(CAGD_ERR_BZR_CRV_EXPECT);
-
- Crv1 = CagdCrvCopy(Crv1);
- Crv2 = CagdCrvCopy(Crv2);
- if (!CagdMakeCrvsCompatible(&Crv1, &Crv2, FALSE, FALSE))
- FATAL_ERROR(CAGD_ERR_CRV_FAIL_CMPT);
-
- ProdCrv = BzrCrvNew(Order = Order1 + Order2 - 1, Crv1 -> PType);
- IsNotRational = !CAGD_IS_RATIONAL_CRV(ProdCrv);
- MaxCoord = CAGD_NUM_OF_PT_COORD(ProdCrv -> PType);
-
- Points = ProdCrv -> Points;
- Points1 = Crv1 -> Points;
- Points2 = Crv2 -> Points;
-
- for (i = 0; i < Order; i++)
- for (k = IsNotRational; k <= MaxCoord; k++)
- Points[k][i] = 0.0;
-
- for (i = 0; i < Order1; i++) {
- for (j = 0; j < Order2; j++) {
- CagdRType
- Coef = CagdIChooseK(i, Degree1) *
- CagdIChooseK(j, Degree2) /
- CagdIChooseK(i + j, Degree1 + Degree2);
-
- for (k = IsNotRational; k <= MaxCoord; k++)
- Points[k][i+j] += Coef * Points1[k][i] * Points2[k][j];
- }
- }
-
- CagdCrvFree(Crv1);
- CagdCrvFree(Crv2);
-
- return ProdCrv;
- }
-
- /******************************************************************************
- * Given two bezier curve lists - multiply them one at a time. *
- * Return a bezier curve lists representing their products. *
- ******************************************************************************/
- CagdCrvStruct *BzrCrvMultList(CagdCrvStruct *Crv1Lst, CagdCrvStruct *Crv2Lst)
- {
- CagdCrvStruct *Crv1, *Crv2,
- *ProdCrvTail = NULL,
- *ProdCrvList = NULL;
-
- for (Crv1 = Crv1Lst, Crv2 = Crv2Lst;
- Crv1 != NULL && Crv2 != NULL;
- Crv1 = Crv1 -> Pnext, Crv2 = Crv2 -> Pnext) {
- CagdCrvStruct
- *ProdCrv = BzrCrvMult(Crv1, Crv2);
-
- if (ProdCrvList == NULL)
- ProdCrvList = ProdCrvTail = ProdCrv;
- else {
- ProdCrvTail -> Pnext = ProdCrv;
- ProdCrvTail = ProdCrv;
- }
- }
-
- return ProdCrvList;
- }
-
- /******************************************************************************
- * Given two bezier surfaces - multiply them coordinatewise. *
- * The two surfaces are promoted to same point type before the multiplication *
- * can take place. *
- * Return a bezier surface representing their product. *
- ******************************************************************************/
- CagdSrfStruct *BzrSrfMult(CagdSrfStruct *Srf1, CagdSrfStruct *Srf2)
- {
- CagdBType IsNotRational;
- int i, j, k, l, m, MaxCoord, UOrder, VOrder,
- UOrder1 = Srf1 -> UOrder,
- VOrder1 = Srf1 -> VOrder,
- UOrder2 = Srf2 -> UOrder,
- VOrder2 = Srf2 -> VOrder,
- UDegree1 = UOrder1 - 1,
- VDegree1 = VOrder1 - 1,
- UDegree2 = UOrder2 - 1,
- VDegree2 = VOrder2 - 1;
- CagdSrfStruct *ProdSrf;
- CagdRType **Points, **Points1, **Points2;
-
- if (!CAGD_IS_BEZIER_SRF(Srf1) || !CAGD_IS_BEZIER_SRF(Srf2))
- FATAL_ERROR(CAGD_ERR_BZR_SRF_EXPECT);
-
- Srf1 = CagdSrfCopy(Srf1);
- Srf2 = CagdSrfCopy(Srf2);
- if (!CagdMakeSrfsCompatible(&Srf1, &Srf2, FALSE, FALSE, FALSE, FALSE))
- FATAL_ERROR(CAGD_ERR_SRF_FAIL_CMPT);
-
- ProdSrf = BzrSrfNew(UOrder = UOrder1 + UOrder2 - 1,
- VOrder = VOrder1 + VOrder2 - 1, Srf1 -> PType);
- IsNotRational = !CAGD_IS_RATIONAL_SRF(ProdSrf);
- MaxCoord = CAGD_NUM_OF_PT_COORD(ProdSrf -> PType);
-
- Points = ProdSrf -> Points;
- Points1 = Srf1 -> Points;
- Points2 = Srf2 -> Points;
-
- for (k = IsNotRational; k <= MaxCoord; k++) {
- CagdRType
- *Pts = Points[k];
-
- for (i = 0; i < UOrder * VOrder; i++)
- *Pts++ = 0.0;
- }
-
- for (i = 0; i < UOrder1; i++) {
- for (j = 0; j < VOrder1; j++) {
- for (l = 0; l < UOrder2; l++) {
- for (m = 0; m < VOrder2; m++) {
- int Index = CAGD_MESH_UV(ProdSrf, i + l, j + m),
- Index1 = CAGD_MESH_UV(Srf1, i, j),
- Index2 = CAGD_MESH_UV(Srf2, l, m);
- CagdRType
- Coef1 = CagdIChooseK(i, UDegree1) *
- CagdIChooseK(l, UDegree2) /
- CagdIChooseK(i + l, UDegree1 + UDegree2),
- Coef2 = CagdIChooseK(j, VDegree1) *
- CagdIChooseK(m, VDegree2) /
- CagdIChooseK(j + m, VDegree1 + VDegree2);
-
- for (k = IsNotRational; k <= MaxCoord; k++)
- Points[k][Index] += Coef1 * Coef2 *
- Points1[k][Index1] * Points2[k][Index2];
- }
- }
- }
- }
-
- CagdSrfFree(Srf1);
- CagdSrfFree(Srf2);
-
- return ProdSrf;
- }
-
- /******************************************************************************
- * Given a rational bezier curve - computes its derivative curve using the *
- * quotient rule for differentiation. *
- ******************************************************************************/
- CagdCrvStruct *BzrCrvDeriveRational(CagdCrvStruct *Crv)
- {
- CagdCrvStruct *CrvW, *CrvX, *CrvY, *CrvZ, *DCrvW, *DCrvX, *DCrvY, *DCrvZ,
- *TCrv1, *TCrv2, *DeriveCrv;
-
- CagdCrvSplitScalar(Crv, &CrvW, &CrvX, &CrvY, &CrvZ);
- if (CrvW)
- DCrvW = BzrCrvDerive(CrvW);
- else {
- DCrvW = NULL;
- FATAL_ERROR(CAGD_ERR_RATIONAL_EXPECTED);
- }
-
- if (CrvX) {
- DCrvX = BzrCrvDerive(CrvX);
-
- TCrv1 = BzrCrvMult(DCrvX, CrvW);
- TCrv2 = BzrCrvMult(CrvX, DCrvW);
-
- CagdCrvFree(CrvX);
- CagdCrvFree(DCrvX);
- CrvX = CagdCrvSub(TCrv1, TCrv2);
- CagdCrvFree(TCrv1);
- CagdCrvFree(TCrv2);
- }
-
- if (CrvY) {
- DCrvY = BzrCrvDerive(CrvY);
-
- TCrv1 = BzrCrvMult(DCrvY, CrvW);
- TCrv2 = BzrCrvMult(CrvY, DCrvW);
-
- CagdCrvFree(CrvY);
- CagdCrvFree(DCrvY);
- CrvY = CagdCrvSub(TCrv1, TCrv2);
- CagdCrvFree(TCrv1);
- CagdCrvFree(TCrv2);
- }
-
- if (CrvZ) {
- DCrvZ = BzrCrvDerive(CrvZ);
-
- TCrv1 = BzrCrvMult(DCrvZ, CrvW);
- TCrv2 = BzrCrvMult(CrvZ, DCrvW);
-
- CagdCrvFree(CrvZ);
- CagdCrvFree(DCrvZ);
- CrvZ = CagdCrvSub(TCrv1, TCrv2);
- CagdCrvFree(TCrv1);
- CagdCrvFree(TCrv2);
- }
-
- TCrv1 = BzrCrvMult(CrvW, CrvW);
- CagdCrvFree(CrvW);
- CrvW = TCrv1;
-
- if (!CagdMakeCrvsCompatible(&CrvW, &CrvX, TRUE, TRUE) ||
- !CagdMakeCrvsCompatible(&CrvW, &CrvY, TRUE, TRUE) ||
- !CagdMakeCrvsCompatible(&CrvW, &CrvZ, TRUE, TRUE))
- FATAL_ERROR(CAGD_ERR_CRV_FAIL_CMPT);
-
- DeriveCrv = CagdCrvMergeScalar(CrvW, CrvX, CrvY, CrvZ);
-
- if (CrvX)
- CagdCrvFree(CrvX);
- if (CrvY)
- CagdCrvFree(CrvY);
- if (CrvZ)
- CagdCrvFree(CrvZ);
- if (CrvW) {
- CagdCrvFree(CrvW);
- CagdCrvFree(DCrvW);
- }
-
- return DeriveCrv;
- }
-
- /******************************************************************************
- * Given a rational bezier surface - computes its derivative curve using the *
- * quotient rule for differentiation. *
- ******************************************************************************/
- CagdSrfStruct *BzrSrfDeriveRational(CagdSrfStruct *Srf, CagdSrfDirType Dir)
- {
- CagdSrfStruct *SrfW, *SrfX, *SrfY, *SrfZ, *DSrfW, *DSrfX, *DSrfY, *DSrfZ,
- *TSrf1, *TSrf2, *DeriveSrf;
-
- CagdSrfSplitScalar(Srf, &SrfW, &SrfX, &SrfY, &SrfZ);
- if (SrfW)
- DSrfW = BzrSrfDerive(SrfW, Dir);
- else {
- DSrfW = NULL;
- FATAL_ERROR(CAGD_ERR_RATIONAL_EXPECTED);
- }
-
- if (SrfX) {
- DSrfX = BzrSrfDerive(SrfX, Dir);
-
- TSrf1 = BzrSrfMult(DSrfX, SrfW);
- TSrf2 = BzrSrfMult(SrfX, DSrfW);
-
- CagdSrfFree(SrfX);
- CagdSrfFree(DSrfX);
- SrfX = CagdSrfSub(TSrf1, TSrf2);
- CagdSrfFree(TSrf1);
- CagdSrfFree(TSrf2);
- }
- if (SrfY) {
- DSrfY = BzrSrfDerive(SrfY, Dir);
-
- TSrf1 = BzrSrfMult(DSrfY, SrfW);
- TSrf2 = BzrSrfMult(SrfY, DSrfW);
-
- CagdSrfFree(SrfY);
- CagdSrfFree(DSrfY);
- SrfY = CagdSrfSub(TSrf1, TSrf2);
- CagdSrfFree(TSrf1);
- CagdSrfFree(TSrf2);
- }
- if (SrfZ) {
- DSrfZ = BzrSrfDerive(SrfZ, Dir);
-
- TSrf1 = BzrSrfMult(DSrfZ, SrfW);
- TSrf2 = BzrSrfMult(SrfZ, DSrfW);
-
- CagdSrfFree(SrfZ);
- CagdSrfFree(DSrfZ);
- SrfZ = CagdSrfSub(TSrf1, TSrf2);
- CagdSrfFree(TSrf1);
- CagdSrfFree(TSrf2);
- }
-
- TSrf1 = BzrSrfMult(SrfW, SrfW);
- CagdSrfFree(SrfW);
- SrfW = TSrf1;
-
- if (!CagdMakeSrfsCompatible(&SrfW, &SrfX, TRUE, TRUE, TRUE, TRUE) ||
- !CagdMakeSrfsCompatible(&SrfW, &SrfY, TRUE, TRUE, TRUE, TRUE) ||
- !CagdMakeSrfsCompatible(&SrfW, &SrfZ, TRUE, TRUE, TRUE, TRUE))
- FATAL_ERROR(CAGD_ERR_SRF_FAIL_CMPT);
-
- DeriveSrf = CagdSrfMergeScalar(SrfW, SrfX, SrfY, SrfZ);
-
- if (SrfX)
- CagdSrfFree(SrfX);
- if (SrfY)
- CagdSrfFree(SrfY);
- if (SrfZ)
- CagdSrfFree(SrfZ);
- if (SrfW) {
- CagdSrfFree(SrfW);
- CagdSrfFree(DSrfW);
- }
-
- return DeriveSrf;
- }
-
- /******************************************************************************
- * Given a bezier curve - convert it to (possibly) piecewise cubic. *
- * If the curve is *
- * 1. A cubic - a copy if it is returned. *
- * 2. Lower than cubic - a degree raised (to a cubic) curve is returned. *
- * 3. Higher than cubic - a C^1 piecewise cubic approximation is computed. *
- * Note in this case a list of polynomial cubic curves is returned. Tol is *
- * then used for the distance tolerance error measure for the approximation *
- * If, however, NoRational is set, rational curves of any order will also be *
- * approximated using cubic polynomials. Furthermore if the total length of *
- * control polygon is more than MaxLen, the curve is subdivided until this is *
- * not the case. *
- ******************************************************************************/
- CagdCrvStruct *BzrApproxBzrCrvAsCubics(CagdCrvStruct *Crv, CagdRType Tol,
- CagdRType MaxLen, CagdBType NoRational)
- {
- CagdCrvStruct *TCrv, *CubicCrvs,
- *CubicCrvsMaxLen = NULL;
-
- if (CAGD_IS_RATIONAL_CRV(Crv) && NoRational)
- return BzrApproxBzrCrvAsCubicPoly(Crv, Tol * Tol);
-
- switch (Crv -> Order) {
- case 2:
- CubicCrvs = BzrCrvDegreeRaiseN(Crv, 4);
- break;
- case 3:
- CubicCrvs = BzrCrvDegreeRaise(Crv);
- break;
- case 4:
- CubicCrvs = CagdCrvCopy(Crv);
- default:
- if (Crv -> Order < 4)
- FATAL_ERROR(CAGD_ERR_OUT_OF_RANGE);
- CubicCrvs = BzrApproxBzrCrvAsCubicPoly(Crv, Tol * Tol);
- }
-
- for (TCrv = CubicCrvs; TCrv != NULL; TCrv = TCrv -> Pnext) {
- CagdCrvStruct *TCrv2,
- *MaxLenCrv = CagdLimitCrvArcLen(TCrv, MaxLen);
-
- for (TCrv2 = MaxLenCrv;
- TCrv2 -> Pnext != NULL;
- TCrv2 = TCrv2 -> Pnext);
-
- TCrv2 -> Pnext = CubicCrvsMaxLen;
- CubicCrvsMaxLen = MaxLenCrv;
- }
-
- CagdCrvFreeList(CubicCrvs);
- return CubicCrvsMaxLen;
- }
-
- /******************************************************************************
- * Given a bezier curve with order larger than cubic, approximate it using *
- * piecewise cubic curves. A C^1 continuous approximation is computed so that *
- * the approximation is at most sqrt(Tol2) away from the given curve. *
- * Input curve can be rational, although output is always a polynomial. *
- ******************************************************************************/
- CagdCrvStruct *BzrApproxBzrCrvAsCubicPoly(CagdCrvStruct *Crv, CagdRType Tol2)
- {
- CagdBType
- ApproxOK = TRUE,
- IsNotRational = !CAGD_IS_RATIONAL_CRV(Crv);
- int i,
- Order = Crv -> Order,
- MaxCoord = CAGD_NUM_OF_PT_COORD(Crv -> PType);
- CagdPointType
- PType = Crv -> PType,
- CubicPType = CAGD_MAKE_PT_TYPE(FALSE, MaxCoord);
- CagdCrvStruct *DistSqrCrv, *DiffCrv,
- *CubicBzr = BzrCrvNew(4, CubicPType);
- CagdRType E3Pt1[3], E3Pt2[3], E3Pt3[3], E3Pt4[3], Tan1[3], Tan2[3],
- **CubicPoints = CubicBzr -> Points,
- **Points = Crv -> Points;
-
- CagdCoerceToE3(E3Pt1, Points, 0, PType);
- CagdCoerceToE3(E3Pt2, Points, 1, PType);
- CagdCoerceToE3(E3Pt3, Points, Order - 2, PType);
- CagdCoerceToE3(E3Pt4, Points, Order - 1, PType);
-
- /* End of the two points must match. */
- for (i = 0; i < MaxCoord; i++) {
- CubicPoints[i + 1][0] = E3Pt1[i];
- CubicPoints[i + 1][3] = E3Pt4[i];
- }
-
- /* Tangents at the end of the two points must match. */
- PT_SUB(Tan1, E3Pt2, E3Pt1);
- PT_SUB(Tan2, E3Pt4, E3Pt3);
- PT_SCALE(Tan1, (Order - 1.0) / 3.0);
- PT_SCALE(Tan2, (Order - 1.0) / 3.0);
-
- for (i = 0; i < MaxCoord; i++) {
- CubicPoints[i + 1][1] = E3Pt1[i] + Tan1[i];
- CubicPoints[i + 1][2] = E3Pt4[i] - Tan2[i];
- }
-
- /* Compare the two curves by computed the distance square between */
- /* corresponding parameter values. */
- DiffCrv = CagdCrvSub(Crv, CubicBzr);
- DistSqrCrv = CagdCrvDotProd(DiffCrv, DiffCrv);
- CagdCrvFree(DiffCrv);
- Points = DistSqrCrv -> Points;
- if (IsNotRational) {
- CagdRType
- *Dist = Points[1];
-
- for (i = DistSqrCrv -> Order - 1; i >= 0; i--) {
- if (*Dist++ > Tol2) {
- ApproxOK = FALSE;
- break;
- }
- }
- }
- else {
- CagdRType
- *Dist0 = Points[0],
- *Dist1 = Points[1];
-
- for (i = DistSqrCrv -> Order - 1; i >= 0; i--) {
- if (*Dist1++ / *Dist0++ > Tol2) {
- ApproxOK = FALSE;
- break;
- }
- }
- }
- CagdCrvFree(DistSqrCrv);
-
- if (ApproxOK)
- return CubicBzr;
- else {
- CagdCrvStruct
- *Crv1 = BzrCrvSubdivAtParam(Crv, 0.5),
- *Crv2 = Crv1 -> Pnext,
- *Crv1Approx = BzrApproxBzrCrvAsCubicPoly(Crv1, Tol2),
- *Crv2Approx = BzrApproxBzrCrvAsCubicPoly(Crv2, Tol2);
-
- CagdCrvFree(Crv1);
- CagdCrvFree(Crv2);
-
- for (Crv1 = Crv1Approx; Crv1 -> Pnext != NULL; Crv1 = Crv1 ->Pnext);
- Crv1 -> Pnext = Crv2Approx;
- return Crv1Approx;
- }
- }
-
-